package com.edu.scnu.controller;

import java.util.List;
import java.util.Map;

import com.edu.scnu.element.ElementObj;
import com.edu.scnu.element.Enemy;
import com.edu.scnu.element.Play;
import com.edu.scnu.manager.ElementManager;
import com.edu.scnu.manager.GameElement;
import com.edu.scnu.manager.GameLoad;

/**
 * @说明 游戏的主线程，用于控制游戏的加载，游戏关卡，游戏运行时自动化 游戏判定，游戏地图切换，资源释放和重新读取等……
 * @author 14737
 * @继承 使用继承的方式实现多线程（一般建议使用接口实现）
 */
public class GameThread extends Thread {
    private ElementManager em = ElementManager.getManager();
    private int mapId = 1;// 关卡id
    private boolean win = true;// 用于判定是打赢了还是输了，这里跟输出内容是下一关还是失败关闭有关
    private List<ElementObj> enemyList;// 用一个集合暂存创建的对象

    @Override
    public void run() {// 游戏的run方法 主线程
        boolean bl = true;
        while (bl) { // 扩展，可以将true变为一个变量用于控制结束
            // 游戏开始前 读进度条，加载游戏资源（场景资源）
            if (gameLoad(mapId)) {
                // 游戏进行时 游戏过程中
                gameRun(mapId);
                // 游戏场景结束时 游戏资源回收（场景资源）
                bl = gameOver();
            } else {
                break;
            }
            try {
                sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.exit(0);
    }

    /**
     * 游戏的加载
     */
    private boolean gameLoad(int mapId) {
        GameLoad.loadImg(); // 记载图片
        GameLoad.MapLoad(this.mapId); // 加载地图
        // 加载主角
        GameLoad.loadPlay(); // 也可以带参数，单机还是2人
        // ElementObj element = new Enemy().createElement("0,0,1,0");
        // em.addElement(element, GameElement.ENEMY);

        // 加载敌人NPC等 因为要实现随时间加载敌人，所以将敌人的加载放到gamerun里
        GameLoad.loadBoss(mapId);
        GameLoad.loadEnemy(mapId);
        // 全部加载完成，游戏启动
        if (em.getElementsByKey(GameElement.ENEMY).isEmpty() && em.getElementsByKey(GameElement.BOSS).isEmpty()) {
        	return false;
        }
        else {
        	return true;
        }
    }

    /**
     * @说明 游戏进行时
     * @任务说明 游戏过程中需要做的事情： 1.自动化玩家的移动，碰撞，死亡 2.新元素的增加(NPC死亡后出现道具) 3.游戏暂停等…… 先实现主角的移动
     */
    private long gameTime = 1L;

    private void gameRun(int guanqiaid) {
        while (true) { // 预留扩展true可以变为变量，用于控制关卡结束等
            // System.out.println(gameTime);
            Map<GameElement, List<ElementObj>> all = em.getGameElements();
            List<ElementObj> plays = em.getElementsByKey(GameElement.PLAY);
            List<ElementObj> enemys = em.getElementsByKey(GameElement.ENEMY);
            List<ElementObj> bosses = em.getElementsByKey(GameElement.BOSS);
            // List<ElementObj> files = em.getElementsByKey(GameElement.PLAYFILE);
            // List<ElementObj> enemyFiles = em.getElementsByKey(GameElement.ENEMYFILE);
            // List<ElementObj> maps = em.getElementsByKey(GameElement.MAPS);
            // List<ElementObj> items = em.getElementsByKey(GameElement.GAMEITEM);
            moveAndUpdate(all, gameTime); // 游戏元素自动化方法
            ElementPK(GameElement.ENEMY, GameElement.PLAYFILE);
            // ElementPK(GameElement.ENEMYFILE, GameElement.PLAYFILE);
            ElementPK(GameElement.PLAY, GameElement.ENEMYFILE);
            ElementPK(GameElement.PLAY, GameElement.GAMEITEM);
            ElementPK(GameElement.PLAY, GameElement.ENEMY);
            ElementPK(GameElement.BOSS, GameElement.PLAYFILE);
            ElementPK(GameElement.PLAY, GameElement.BOSS);

            // 测试进入结束
            // 此处需要修改进入结束的逻辑
            gameTime++; // 唯一时间控制
            if (plays.isEmpty()) {
                this.win = false;// 玩家失败
                return;
            } else if (enemys.isEmpty() && bosses.isEmpty()) {
                this.win = true;
                return;
            }

            try {
                sleep(10); // 默认理解为1秒刷新100次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @说明 两个元素进行攻击
     * @param listA
     * @param listB 默认把子弹放第二个
     */
    public void ElementPK(GameElement a, GameElement b) {
        List<ElementObj> list1 = em.getElementsByKey(a);
        List<ElementObj> list2 = em.getElementsByKey(b);

        // 在这里使用循环，做一对一判定，如果为真，就设置2个对象的死亡状态
        for (int i = 0; i < list1.size(); i++) {
            ElementObj A = list1.get(i);
            for (int j = 0; j < list2.size(); j++) {
                ElementObj B = list2.get(j);
                if (A.pk(B)) {
                    A.beAttacked(B.getAttack());
                    B.beAttacked(A.getAttack());
                    // System.err.println(A + "attack" + B);
                    if (A instanceof Enemy) {
                        Play.score++;
                    }
                }
            }
        }
    }

    // 游戏元素自动化方法
    public void moveAndUpdate(Map<GameElement, List<ElementObj>> all, long gameTime) {
        // GameElement.values(); // 隐藏方法，返回值是一个数组，数组的顺序就是定义枚举的顺序
        for (GameElement ge : GameElement.values()) {
            List<ElementObj> list = all.get(ge);
            for (int i = list.size() - 1; i >= 0; i--) {
                ElementObj obj = list.get(i); // 调用为基类
                if (!obj.isLive()) {
                    // 启动一个死亡方法（方法中可以做事情，如：死亡动画，掉装备）
                    obj.die(gameTime);
                    if (obj.isCanRmove()) {
                    	list.remove(i);
                    }
                    continue;
                }
                obj.model(gameTime); // 调用每个类的自己的show方法完成自己的显示
            }
        }
    }

    /**
     * @说明 游戏切换关卡。关卡转换已成功
     */
    private boolean gameOver() {
        List<ElementObj> play = em.getGameElements().get(GameElement.PLAY);
        // List<ElementObj> maps = em.getGameElements().get(GameElement.MAPS);
        // List<ElementObj> files = em.getElementsByKey(GameElement.PLAYFILE);
        String str;
        if (this.win) {
        	if (mapId >= 5) {
        		str = "你的分数为：" + ((Play) play.get(0)).getScore() + ";恭喜通关，感谢您的游玩";
        		for (GameElement e : GameElement.values()) {
                    em.getGameElements().get(e).clear();
                }
        		GameLoad.loadText(str);
        		 try {
                     sleep(3000);
                 } catch (InterruptedException e1) {
                     e1.printStackTrace();
                 }
        		return false;
        	}
        	else {
        		str = "你的分数为：" + ((Play) play.get(0)).getScore() + ";进入下一关";
        	}
            Play.score = 0;
        } else {
            str = "你失败了，游戏结束;请再接再厉";
            for (GameElement e : GameElement.values()) {
                em.getGameElements().get(e).clear();
            }
            GameLoad.loadText(str);
            try {
                sleep(3000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            return false;
        }
        for (GameElement e : GameElement.values()) {
            em.getGameElements().get(e).clear();
        }
        GameLoad.loadText(str);
        try {
            sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        gameTime = 1;// 关卡结束后将时间置1
        try {
            sleep(2000);
            List<ElementObj> scores = em.getElementsByKey(GameElement.TEXT);
            scores.clear();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mapId++;
        return true;
    }

}
